﻿using Devonline.Entity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Devonline.AspNetCore.OData;

/// <summary>
/// 基于 OData 和 DataService 的数据增删改查的基础控制器
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
/// <typeparam name="TViewModel">业务数据类型的视图模型类型</typeparam>
/// <typeparam name="TKey">主键类型</typeparam>
[Authorize]
[ApiController]
public abstract class ODataModelExportServiceController<TDbContext, TEntitySet, TViewModel, TKey>(
    ILogger<ODataModelExportServiceController<TDbContext, TEntitySet, TViewModel, TKey>> logger,
    IDataService<TDbContext, TEntitySet, TKey> dataService,
    IExcelExportService excelExportService) :
    ODataModelServiceController<TDbContext, TEntitySet, TViewModel, TKey>(logger, dataService)
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet<TKey>, new()
    where TViewModel : class, IViewModel<TKey>, new()
    where TKey : IConvertible
{
    protected readonly IExcelExportService _excelExportService = excelExportService;

    /// <summary>
    /// 返回导出为当前业务数据类型的基础方法
    /// 包含隐式的过滤条件和文件名参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("Export")]
    public virtual async Task<IActionResult> ExportAsync(ODataQueryOptions<TEntitySet> options) => await _excelExportService.ExportAsync(await ExportAsync<TViewModel>(options, default));

    /// <summary>
    /// 返回导出为当前业务数据类型的基础方法
    /// </summary>
    /// <param name="options">odata 查询表达式</param>
    /// <param name="fileName">导出的文件名</param>
    /// <returns></returns>
    protected virtual async Task<ExcelData<TEntitySet>> ExportAsync(ODataQueryOptions<TEntitySet> options, string? fileName = default)
    {
        _logger.LogInformation("用户 {userName} 开始导出 {typeName}!", _dataService.UserName, _dataService.TypeName);
        return new ExcelData<TEntitySet>
        {
            FileName = fileName ?? Request.GetRequestOption<string>(nameof(fileName)),
            Columns = Request.GetRequestColumns<TEntitySet>(),
            Data = await options.ApplyToAsync(_dataService.GetQueryable())
        };
    }
    /// <summary>
    /// 返回导出为 TResult 类型的基础方法
    /// </summary>
    /// <typeparam name="TResult">导出的类型</typeparam>
    /// <param name="options">odata 查询表达式</param>
    /// <param name="fileName">导出的文件名</param>
    /// <returns></returns>
    protected virtual async Task<ExcelData<TResult>> ExportAsync<TResult>(ODataQueryOptions<TEntitySet> options, string? fileName = default) where TResult : class, new()
    {
        _logger.LogInformation("用户 {userName} 开始导出 {typeName}!", _dataService.UserName, _dataService.TypeName);
        return new ExcelData<TResult>
        {
            FileName = fileName ?? Request.GetRequestOption<string>(nameof(fileName)),
            Columns = Request.GetRequestColumns<TResult>(),
            Data = await options.ApplyToAsync<TEntitySet, TResult>(_dataService.GetQueryable())
        };
    }
}

/// <summary>
/// 基于字符串作为主键的 OData 和 DataService 的数据增删改查的基础控制器
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
/// <typeparam name="TViewModel">业务数据类型的视图模型类型</typeparam>
[Authorize]
[ApiController]
public abstract class ODataModelExportServiceController<TDbContext, TEntitySet, TViewModel>(
    ILogger<ODataModelExportServiceController<TDbContext, TEntitySet, TViewModel>> logger,
    IDataService<TDbContext, TEntitySet> dataService,
    IExcelExportService excelExportService) :
    ODataModelExportServiceController<TDbContext, TEntitySet, TViewModel, string>(logger, dataService, excelExportService)
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet, new()
    where TViewModel : class, IViewModel, new()
{ }